package org.nehc.algorithm.redissonutils;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;

import java.time.Duration;

/**
 * Redisson 限流操作工具类
 * 提供限流相关操作
 *
 * @author system
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class RedissonRateLimiterUtils {

    private static final RedissonClient CLIENT = RedissonUtils.getClient();

    // ==================== 限流器操作 ====================

    /**
     * 初始化限流器
     *
     * @param key      限流器key
     * @param rateType 限流类型
     * @param rate     速率
     * @param rateInterval 速率间隔
     * @return true=初始化成功；false=初始化失败
     */
    public static boolean initRateLimiter(String key, RateType rateType, long rate, Duration rateInterval) {
        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        return rateLimiter.trySetRate(rateType, rate, rateInterval);
    }

    /**
     * 初始化限流器（每秒限流）
     *
     * @param key  限流器key
     * @param rate 每秒允许的请求数
     * @return true=初始化成功；false=初始化失败
     */
    public static boolean initRateLimiterPerSecond(String key, long rate) {
        return initRateLimiter(key, RateType.OVERALL, rate, Duration.ofSeconds(1));
    }

    /**
     * 初始化限流器（每分钟限流）
     *
     * @param key  限流器key
     * @param rate 每分钟允许的请求数
     * @return true=初始化成功；false=初始化失败
     */
    public static boolean initRateLimiterPerMinute(String key, long rate) {
        return initRateLimiter(key, RateType.OVERALL, rate, Duration.ofMinutes(1));
    }

    /**
     * 初始化限流器（每小时限流）
     *
     * @param key  限流器key
     * @param rate 每小时允许的请求数
     * @return true=初始化成功；false=初始化失败
     */
    public static boolean initRateLimiterPerHour(String key, long rate) {
        return initRateLimiter(key, RateType.OVERALL, rate, Duration.ofHours(1));
    }

    /**
     * 初始化限流器（每天限流）
     *
     * @param key  限流器key
     * @param rate 每天允许的请求数
     * @return true=初始化成功；false=初始化失败
     */
    public static boolean initRateLimiterPerDay(String key, long rate) {
        return initRateLimiter(key, RateType.OVERALL, rate, Duration.ofDays(1));
    }

    /**
     * 尝试获取许可（非阻塞）
     *
     * @param key 限流器key
     * @return true=获取成功；false=获取失败
     */
    public static boolean tryAcquire(String key) {
        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        return rateLimiter.tryAcquire();
    }

    /**
     * 尝试获取指定数量的许可（非阻塞）
     *
     * @param key     限流器key
     * @param permits 许可数量
     * @return true=获取成功；false=获取失败
     */
    public static boolean tryAcquire(String key, long permits) {
        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        return rateLimiter.tryAcquire(permits);
    }

    /**
     * 尝试在指定时间内获取许可
     *
     * @param key     限流器key
     * @param timeout 超时时间
     * @return true=获取成功；false=获取失败
     */
    public static boolean tryAcquire(String key, Duration timeout) {
        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        return rateLimiter.tryAcquire(timeout);
    }

    /**
     * 尝试在指定时间内获取指定数量的许可
     *
     * @param key     限流器key
     * @param permits 许可数量
     * @param timeout 超时时间
     * @return true=获取成功；false=获取失败
     */
    public static boolean tryAcquire(String key, long permits, Duration timeout) {
        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        return rateLimiter.tryAcquire(permits, timeout);
    }

    /**
     * 获取许可（阻塞）
     *
     * @param key 限流器key
     */
    public static void acquire(String key) {
        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        rateLimiter.acquire();
    }

    /**
     * 获取指定数量的许可（阻塞）
     *
     * @param key     限流器key
     * @param permits 许可数量
     */
    public static void acquire(String key, long permits) {
        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        rateLimiter.acquire(permits);
    }

    /**
     * 获取可用许可数
     *
     * @param key 限流器key
     * @return 可用许可数
     */
    public static long availablePermits(String key) {
        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        return rateLimiter.availablePermits();
    }

    /**
     * 设置限流器速率
     *
     * @param key      限流器key
     * @param rateType 限流类型
     * @param rate     速率
     * @param rateInterval 速率间隔
     */
    public static void setRate(String key, RateType rateType, long rate, Duration rateInterval) {
        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        rateLimiter.setRate(rateType, rate, rateInterval);
    }

    /**
     * 获取限流器配置信息
     *
     * @param key 限流器key
     * @return 限流器配置信息
     */
    public static org.redisson.api.RateLimiterConfig getConfig(String key) {
        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        return rateLimiter.getConfig();
    }

    /**
     * 删除限流器
     *
     * @param key 限流器key
     * @return true=删除成功；false=删除失败
     */
    public static boolean deleteRateLimiter(String key) {
        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        return rateLimiter.delete();
    }

    /**
     * 检查限流器是否存在
     *
     * @param key 限流器key
     * @return true=存在；false=不存在
     */
    public static boolean isExists(String key) {
        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        return rateLimiter.isExists();
    }

    /**
     * 设置限流器过期时间
     *
     * @param key      限流器key
     * @param duration 过期时间
     * @return true=设置成功；false=设置失败
     */
    public static boolean expire(String key, Duration duration) {
        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        return rateLimiter.expire(duration);
    }

    /**
     * 清除限流器过期时间
     *
     * @param key 限流器key
     * @return true=清除成功；false=清除失败
     */
    public static boolean clearExpire(String key) {
        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        return rateLimiter.clearExpire();
    }

    /**
     * 获取限流器剩余过期时间
     *
     * @param key 限流器key
     * @return 剩余过期时间（毫秒），-1表示永不过期，-2表示不存在
     */
    public static long remainTimeToLive(String key) {
        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        return rateLimiter.remainTimeToLive();
    }

    // ==================== 便捷方法 ====================

    /**
     * 简单限流检查（每秒限流）
     *
     * @param key  限流器key
     * @param rate 每秒允许的请求数
     * @return true=通过限流；false=被限流
     */
    public static boolean checkRateLimit(String key, long rate) {
        if (!isExists(key)) {
            initRateLimiterPerSecond(key, rate);
        }
        return tryAcquire(key);
    }

    /**
     * 简单限流检查（自定义时间间隔）
     *
     * @param key          限流器key
     * @param rate         允许的请求数
     * @param rateInterval 时间间隔
     * @return true=通过限流；false=被限流
     */
    public static boolean checkRateLimit(String key, long rate, Duration rateInterval) {
        if (!isExists(key)) {
            initRateLimiter(key, RateType.OVERALL, rate, rateInterval);
        }
        return tryAcquire(key);
    }

    /**
     * 获取下次可用时间（毫秒）
     *
     * @param key 限流器key
     * @return 下次可用时间（毫秒），0表示立即可用
     */
    public static long getNextAvailableTime(String key) {
        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        if (rateLimiter.tryAcquire()) {
            // 如果能立即获取到许可，说明立即可用
            return 0;
        }

        // 尝试获取配置信息来计算下次可用时间
        try {
            org.redisson.api.RateLimiterConfig config = rateLimiter.getConfig();
            if (config != null) {
                long intervalInMillis = config.getRateInterval() * 1000; // 转换为毫秒
                return intervalInMillis / config.getRate();
            }
        } catch (Exception e) {
            log.warn("Failed to get rate limiter config for key: {}", key, e);
        }

        return 1000; // 默认返回1秒
    }
}
